# coding=utf8
import SocketServer
import struct
from protocol.uplink.packet import *
from protocol.uplink import decode
from protocol.uplink import frameFactory
import logging

import AFN_02
import AFN_0A
import AFN_0C


class ConcentHandler(SocketServer.StreamRequestHandler):
    def setup(self):
        global users
        sid = id(self.request)
        users[sid] = {}
        users[sid]['socket_id'] = self.request
        users[sid]['nickname'] = sid
        print users[sid]['nickname'], "加入".decode("utf-8"), "\0"

        self.frameDecoder = decode.FrameDecode()

    def finish(self):
        # 断开就删除用户
        global users
        self.request.close()
        print users[id(self.request)]['nickname'], "离开".decode("utf-8")
        del users[id(self.request)]

    def handle(self):
        while (True):
            mdata = self.request.recv(2048)
            if not mdata:
                break
            else:
                remain = struct.unpack('B' * len(mdata), mdata)
                while len(remain) > 0:
                    frameRaw, remain = self.frameDecoder.decode(remain)
                    if frameRaw:
                        address = frameRaw[4:12]
                        # 解出用户数据域
                        try:
                            decoder = ServerDataRegionDecode(frameRaw[14:-3])
                            dataRegion = decoder.decodeDataRegion()
                            frame = Frame(dataRegion, address)
                            print "recv frame:", frame.info()
                            print  byteUtil.formatBytes(frameRaw)
                            cmd = dataRegion.AFN.CMD

                            if cmd == 0:
                                continue

                            afn = frame.dataRegion.AFN
                            seq = frame.dataRegion.SEQ

                            module = eval("AFN_%02X" % afn.CMD)

                            results = []
                            for unit in dataRegion.dataUnits:
                                fn = unit.FN
                                str = "module.fn_%d" % fn
                                func = eval(str)
                                if func:
                                    print("exec AFN:%02x FN:%d" % (afn.CMD, fn))
                                    value = func(unit)
                                    results.append(value)

                            if len(results) > 0:
                                ack = frameFactory.ACK(frame)
                                self.send(ack)


                                # if cmd == 02:
                                # ack = frameFactory.ACK(frame)
                                # self.send(ack)
                                #
                                # if cmd == 0x0e:
                                # ack = frameFactory.ACK(frame)
                                # self.send(ack)

                        except Exception as e:
                            print e


    def send(self, frame):
        raw = frame.encode()
        print "send:", frame.info()
        print( byteUtil.formatBytes(frame.raw))

        self.request.send(frame.pack())


def sendToAllClient(frame):
    if isinstance(frame, Frame):
        print "send:", frame.info()
        raw = frame.encode()
        print byteUtil.formatBytes(raw)
        bytes = frame.pack()
    else:
        print "send:", byteUtil.formatBytes(frame)
        bytes = struct.pack('B' * len(frame), *frame)
    global users
    for i in users:
        users[i]['socket_id'].send(bytes)


class ServerDataRegionDecode(decode.DataRegionDecode):
    def __init__(self, raw):
        decode.DataRegionDecode.__init__(self, raw)

    def decodeDataUnit(self, raw):
        da = raw[0:2]
        dt = raw[2:4]

        unit = DataUnit(da, dt)

        dataSize = getUnitDataSize(self.afn.CMD, unit.FN, raw[4:])

        if dataSize == -2:
            dataSize = decode.getUnitDataSize(self.afn.CMD, unit.FN, raw[4:])

        end = dataSize + 4
        unitData = raw[4:end]
        unit.rawData = unitData

        unit.raw = raw[:end]
        return unit, raw[end:]


_data_unit_size = {
    'afn_2': {
        'f1': 0,
        'f3': 1,
    },
    'afn_a': {
        'f1': 4,
        'f2': 22,
        'f3': 24,
        'f4': 27,
        'f5': 5,
        'f6': 12,
        'f9': -1,
        'f11': 7,
        'f12': 4,
        'f13': -1,
        'f17': -1,
        'f18': -1,
        'f19': -1,
        'f20': -1
    },
    'afn_c': {
        'f11': -1,
        'f12': -1,
        'f33': 2,
        'f34': 2,
        'f35': 3,
        'f36': 2,
        'f37': 2,
        'f38': 2,
        'f39': 2
    },
    'afn_e': {
        'f1': -1,
    }
}


def getUnitDataSize(afn, fn, raw):
    try:
        key = "afn_%x" % afn
        sizeDict = _data_unit_size[key]

        key = "f%d" % fn

        if not sizeDict.has_key(key):
            logging.warn("afn:%d ,fn:%d ,unknow size" % (afn, fn))
            return -2
        else:
            size = sizeDict[key]
            if size != -1:
                return size
            else:
                str = "afn%02x_fn%02d_size" % (afn, fn)
                func = eval(str)
                if func:
                    size = func(raw)
                return size
    except:
        return -2


def afn0a_fn09_size(raw):
    dayCount = byteUtil.decodeShort(raw[2:4])
    return dayCount * 4 + 4


def afn0a_fn17_size(raw):
    termNum = raw[0]
    return termNum * 16 + 1


def afn0a_fn18_size(raw):
    lampNum = raw[0]
    return lampNum * 6 + 1


def afn0a_fn19_size(raw):
    count = raw[1]
    return count * 11 + 2


def afn0a_fn13_size(raw):
    count = raw[1]
    return count * 11 + 2


def afn0a_fn20_size(raw):
    return raw[0] + 1


def afn0c_fn11_size(raw):
    return raw[0] * 4 + 2


def afn0c_fn12_size(raw):
    return raw[0] * 2 + 2


def afn0e_fn01_size(raw):
    start = raw[2]
    end = raw[3]
    count = 0
    if start < end:
        count = end - start
    else:
        count = 255 + end - start

    return count * 10 + 4


users = {}


def startServer():
    hostname = "0.0.0.0"
    # port = 5800
    port = 8483
    server = SocketServer.ThreadingTCPServer((hostname, port), ConcentHandler)
    print "server started on", port
    server.serve_forever()


if __name__ == '__main__':
    startServer()

